#include <jni.h>
#include <string>

#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <unistd.h>
#include <sys/inotify.h>
/* 宏定义begin */
//清0宏
#define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize)
//LOG宏定义
#define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg)
#define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg)
#define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg)
#define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg)

/* 内全局变量begin */
static char c_TAG[] = "OnAppUninstall";
static jboolean b_IS_COPY = JNI_TRUE;

extern "C"{
    JNIEXPORT jstring JNICALL
    Java_com_wj_uninstall_UninstallUtils_startWork(
            JNIEnv* env,
            jobject thiz,
            jstring dirStr,
            jstring data_packagedir,
            jstring activity,
            jstring action,
            jstring action_data,
            jstring userSerial) {


        jstring tag = env->NewStringUTF(c_TAG);

        LOG_DEBUG(env->GetStringUTFChars( tag, &b_IS_COPY),
                  env->GetStringUTFChars(env->NewStringUTF( "start------------------"),&b_IS_COPY));
        //初始化log
        LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                  env->GetStringUTFChars(env->NewStringUTF( "init OK"),&b_IS_COPY));


        //fork子进程，以执行轮询任务
        pid_t pid = fork();
        char showpid[10];
        sprintf(showpid, "%d", pid);

        LOG_INFO(env->GetStringUTFChars(tag, &b_IS_COPY),
                 env->GetStringUTFChars(env->NewStringUTF(showpid),&b_IS_COPY));

        if (pid < 0) {
            //出错log
            LOG_ERROR(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("fork failed !!!"),&b_IS_COPY));
        }else if (pid == 0) {
            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("childen process"),&b_IS_COPY));

            int fileDescriptor = inotify_init();
            if (fileDescriptor < 0) {
                //初始化文件监听器失败
                LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                          env->GetStringUTFChars(env->NewStringUTF("inotify_init failed !!!"), &b_IS_COPY));
                exit(1);
            }

            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("will creat a lockfile"),&b_IS_COPY));
            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),env->GetStringUTFChars(dirStr, &b_IS_COPY));
            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("creat a new process"),
                                                &b_IS_COPY));

            //子进程注册"/data/data/{package}"目录监听器
            int watchDescriptor;
            watchDescriptor = inotify_add_watch(fileDescriptor,env->GetStringUTFChars(dirStr, &b_IS_COPY), IN_DELETE);
            if (watchDescriptor < 0) {
                LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                          env->GetStringUTFChars(env->NewStringUTF("inotify_add_watch failed !!!"),&b_IS_COPY));
                exit(1);
            }

            //分配缓存，以便读取event，缓存大小=一个struct inotify_event的大小，这样一次处理一个event
            void *p_buf = malloc(sizeof(struct inotify_event));
            if (p_buf == NULL) {
                LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                          env->GetStringUTFChars(env->NewStringUTF("malloc failed !!!"),
                                                    &b_IS_COPY));
                exit(1);
            }

            //开始监听
            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("start observer"),
                                                &b_IS_COPY));
            size_t readBytes = read(fileDescriptor, p_buf,
                                    sizeof(struct inotify_event));
            //等待2秒
            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("sleep 2 seconds"),
                                                &b_IS_COPY));
            sleep(2);

            //如果是覆盖安装跳过
            FILE *p_appDir = fopen(env->GetStringUTFChars(data_packagedir,&b_IS_COPY), "r");
            if (p_appDir != NULL) {
                LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                          env->GetStringUTFChars(env->NewStringUTF("reinstall"),
                                                    &b_IS_COPY));
                exit(1);
            }

            //read会阻塞进程，走到这里说明收到目录被删除的事件，注销监听器
            free(p_buf);
            inotify_rm_watch(fileDescriptor, IN_DELETE);

            //目录不存在log
            LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("uninstalled"), &b_IS_COPY));

            //执行命令am start -a android.intent.action.VIEW -d http://ww.baidu.com
            // execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d", "http://ww.baidu.com", (char *)NULL);

            //4.2以上的系统由于用户权限管理更严格，需要加上 --user 0
            if (userSerial == NULL) {
                // 执行命令am start -a android.intent.action.VIEW -d $(url)
                execlp("am", "am", "start", "-a", "android.intent.action.VIEW",
                       "-d", env->GetStringUTFChars(action_data, &b_IS_COPY),
                       (char *) NULL);
            }else {
                if (activity == NULL
                    || env->GetStringUTFLength(activity) < 1) {
                    execlp("am", "am", "start", "--user",
                           env->GetStringUTFChars(userSerial, &b_IS_COPY),
                           "-a",
                           env->GetStringUTFChars(action, &b_IS_COPY),
                           "-d", env->GetStringUTFChars(action_data, &b_IS_COPY),
                           (char *) NULL);
                } else {
                    if (action == NULL
                        || env->GetStringUTFLength(action) < 1) {
                        if (action_data == NULL
                            || env->GetStringUTFLength(action_data) < 1) {
                            execlp("am", "am", "start", "--user",
                                   env->GetStringUTFChars(userSerial,
                                                             &b_IS_COPY), "-n",
                                   env->GetStringUTFChars(activity,
                                                             &b_IS_COPY), (char *) NULL);
                        } else {
                            execlp("am", "am", "start", "--user",
                                   env->GetStringUTFChars(userSerial,
                                                             &b_IS_COPY), "-n",
                                   env->GetStringUTFChars(activity,
                                                             &b_IS_COPY), "-d",
                                   env->GetStringUTFChars(action_data,
                                                             &b_IS_COPY), (char *) NULL);
                        }
                    } else {
                        if (action_data == NULL
                            || env->GetStringUTFLength(action_data) < 1) {
                            execlp("am", "am", "start", "--user",
                                   env->GetStringUTFChars(userSerial,
                                                             &b_IS_COPY), "-n",
                                   env->GetStringUTFChars(activity,
                                                             &b_IS_COPY), "-a",
                                   env->GetStringUTFChars(action,
                                                             &b_IS_COPY), (char *) NULL);
                        } else {
                            execlp("am", "am", "start", "--user",
                                   env->GetStringUTFChars(userSerial,
                                                             &b_IS_COPY), "-n",
                                   env->GetStringUTFChars(activity,
                                                             &b_IS_COPY), "-a",
                                   env->GetStringUTFChars(action,
                                                             &b_IS_COPY), "-d",
                                   env->GetStringUTFChars(action_data,
                                                             &b_IS_COPY), (char *) NULL);
                        }
                    }
                }
            }
            //扩展：可以执行其他shell命令，am(即activity manager)，可以打开某程序、服务，broadcast intent，等等
        }else {
            //父进程直接退出，使子进程被init进程领养，以避免子进程僵死
            LOG_DEBUG (env->GetStringUTFChars(tag, &b_IS_COPY),
                      env->GetStringUTFChars(env->NewStringUTF("fork pid > 0"), &b_IS_COPY));
        }
        LOG_DEBUG(env->GetStringUTFChars(tag, &b_IS_COPY),
                  env->GetStringUTFChars(env->NewStringUTF("end------------------"),
                                            &b_IS_COPY));
        return env->NewStringUTF(showpid);
    }
}
